<?php
/**
 * if_mysql驱动
 *
 * @package util.db.drivers
 * @since 0.2
 */
class IDbMysqlDriver extends IAbstractDbDriver {
	/**
	 * Enter description here...
	 *
	 * @var resource
	 */
	private $conn;
	
	private $connected = false;
	
	public function __construct(array $config) {
		parent::__construct($config);
		if (!extension_loaded("mysql")) {
			throw new IDbException("mysql extension not be loaded");
		}
	}
	
	public function getTableList() {
		$result = $this->nativeExec("SHOW TABLES");
		$array = array();
		while ($row = $this->fetch($result, IDb::FETCH_NUM)) {
			$array[] = $row[0];
		}
		return $array;
	}
	
	/**
	 * Enter description here...
	 * 
		 $type;
		 $column;
		 $maxLength = 0;
		 $notNull = false;
		 $primaryKey = false;
		 $autoIncrement = false;
		 $binary = false;
		 $unsigned = false;
		 $hasDefault = false;
		 $defaultValue;
	 *
	 * @param unknown_type $name
	 * @return unknown
	 * @see IDarField
	 * @todo 需要添加除TYPE_STR,TYPE_FLOAT等的其他类型
	 */
	public function describeTable($name) {
		$array = $this->fetchAll($this->nativeExec("DESCRIBE `{$name}`"));
		$fields = array();
		foreach ($array as $row) {
			$field = array();
			$field["column"] = $row["Field"];
			$field["notNull"]  = ($row["Null"] == "No")?true:false;
			$field["primaryKey"] = (strtoupper($row["Key"]) == "PRI");
			$field["unsigned"] = preg_match("/unsigned/", $row["Type"]);
			$field["hasDefault"] = ($row["Default"] != null);
			$field["defaultValue"] = $row["Default"];
			$field["autoIncrement"] = ($row["Extra"] == "auto_increment");
			$matches = array();
			if (preg_match("/^((?:var)?char)\\((\\d+)\\)/", $row["Type"], $matches)) {
                $field["type"] = IDb::TYPE_STR;
                $field["maxLength"] = $matches[2];
            } else if (preg_match("/^decimal\\((\\d+),(\\d+)\\)/", $row["Type"], $matches)) {
                $field["type"] = IDb::TYPE_FLOAT;
                $field["maxLength"] = -1;
            } else if (preg_match("/^((?:small|tiny)?int)\\((\\d+)\\)/", $row["Type"], $matches)) {
                $field["type"] = IDb::TYPE_INT;
       			$field["maxLength"] = -1;	
            } else if (preg_match("/^((?:big|medium)int)\\((\\d+)\\)/", $row["Type"], $matches)) {
            	$field["type"] = IDb::TYPE_LONG;
       			$field["maxLength"] = -1;	
            }
            //其他类型需要添加
            $fields[] = $field;
		}
		return $fields;		
	}
	
	public function connect() {
		//连接
		if ($this->connected) {
			return true;
		}
		
		//连接
		$host = isset($this->config["port"])?$this->config["host"] . ":" . $this->config["port"]:$this->config["host"];
		$host = isset($this->config["socket"])?$this->config["host"] . ":" . $this->config["socket"]:$this->config["host"];
		if ($this->getConfig("persist")) {
			$this->conn = mysql_connect($host, $this->config["username"], $this->config["password"]);
		}
		else {
			$this->conn = mysql_pconnect($host, $this->config["username"], $this->config["password"]);
		}
		
		//数据库
		mysql_select_db($this->config["dbname"], $this->conn);
		
		//字符集
		if (mysql_get_server_info($this->conn) >= "4.1") {
			if ($this->getConfig("charset")) {
				mysql_query("SET NAMES '" . $this->config["charset"] . "'");
			}
		}
		
		$this->connected = true;
		
		return true;
	}
	
	public function close() {
		if ($this->conn) {
			mysql_close($this->conn);
		}
		$this->connected = false;
	}
	
	public function lastInsertId($name = null) {
		$this->init();
		return mysql_insert_id($this->conn);
	}
	
	public function beginTransaction() {
		$this->init();
		mysql_query("START TRANSACTION", $this->conn);
	}
	
	public function commit() {
		$this->init();
		mysql_query("COMMIT", $this->conn);
	}
	
	public function rollBack() {
		$this->init();
		mysql_query("ROLLBACK", $this->conn);
	}
	
	public function limit($sql, $count, $offset = 0) {
		$count = intval($count);
		$offset = intval($offset);
		if ($count < 0) {
			throw new IDbException("sql limit count can not lower than 0");
		}
		if ($offset < 0) {
			throw new IDbException("sql limit offset can not lower than 0");
		}
		if ($count == 0) {
			return $sql;
		}
		return $sql . " LIMIT {$offset},{$count}";
	}
	
	public function quote($data) {
		if (is_int($data) || is_float($data)) {
			return $data;
		}
		if (is_null($data)) {
			return "null";
		}
		$this->init();
		return "'" . mysql_real_escape_string($data, $this->conn) . "'";
	}
	
	public function quoteKeyword($keyword) {
		return "`" . $keyword . "`";
	}
	
	public function exec($sql) {
		$this->init();
		$result = mysql_query($sql, $this->conn);
		$this->free();
		return mysql_affected_rows($this->conn);
	}
	
	public function nativeExec($sql) {
		$this->init();
		$result = mysql_query($sql, $this->conn);
		$this->free();
		return $result;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $sql
	 * @param unknown_type $fetchType
	 * @return IDbStatement
	 */
	public function query($sql, $fetchType = IDb::FETCH_ASSOC) {
		$stmt = $this->prepare($sql);
		$args = func_get_args();
		unset($args[0]);
		call_user_func_array(array($stmt, "setFetchMode"), $args);
		$stmt->execute();
		return $stmt;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $result
	 * @param unknown_type $fetchType
	 * @param unknown_type $arguments
	 * @return unknown
	 * @todo FETCH_OBJ是支持class名
	 */
	public function fetch($result, $fetchType = IDb::FETCH_BOTH, $columnIndex = 0) {
		switch ($fetchType) {
			case IDb::FETCH_BOTH:
				return mysql_fetch_array($result, MYSQL_BOTH);
				break;
			case IDb::FETCH_ASSOC:
				return mysql_fetch_array($result, MYSQL_ASSOC);
			case IDb::FETCH_NUM:
				return mysql_fetch_array($result, MYSQL_NUM);
			case IDb::FETCH_OBJ:
				return mysql_fetch_object($result);
			case IDb::FETCH_COLUMN:
				$row = mysql_fetch_row($result);
				if (!empty($row)) {
					if (array_key_exists($columnIndex, $row)) {
						return $row[$columnIndex];
					}
				}
		}
		return null;
	}
	
	public function fetchAll($result, $fetchType = IDb::FETCH_BOTH, $columnIndex = 0) {
		$array = array();
		$args = func_get_args();
		while ($row = call_user_func_array(array($this, "fetch"), $args)) {
			$array[] = $row;
		}
		return $array;
	}
	
	public function getError() {
		$error = mysql_error();
		if (!$error) {
			return array();
		}
		return array(
			"code" => mysql_errno(),
			"message" => $error
		);
	}
	
	private function init() {
		if (!$this->connected) {
			$this->connect();
		}
	}
	
	private function free($result = null) {
		if (gettype($result) == "resource") {
			mysql_free_result($result);
		}
		$error = $this->getError();
		if (!empty($error)) {
			throw new IDbException($error["message"], $error["code"]);
		}
	}
	
	public function rowCount($result) {
		return mysql_affected_rows($this->conn);
	}
}

?>